using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization;
using System.Windows.Forms;
using System.Workflow.ComponentModel;
using System.Xml;
using System.Xml.Schema;
using OpenComposite.EII.Interfaces;
using OpenComposite.Workflow;
using System.ServiceModel.Description;
using OpenComposite.EII.Repository;

namespace OpenComposite.EII.Designer.Workflow
{
	internal class WorkflowValidator : OpenComposite.EII.Designer.Workflow.IWorkflowValidator
	{
		#region Initialization
		public WorkflowValidator(IServiceProvider serviceProvider)
		{
			_serviceProvider = serviceProvider;

			_repository = _serviceProvider.GetService(typeof(RepositoryService)) as RepositoryService;
			_loader = _serviceProvider.GetService(typeof(System.Workflow.ComponentModel.Design.WorkflowDesignerLoader)) as WorkflowLoader;
			_tasklist = _serviceProvider.GetService(typeof(ITaskListService)) as ITaskListService;
			if ( _tasklist == null ) {
				_messages = new List<string>();
			} else {
				_messages = null;
			}

			_lastindex = -1;
			this.ShowResultMessageBox = true;

			this.HasErrors = false;
			this.HasTasks = false;
			this.HasUnknown = false;
			this.HasWarnings = false;
		}
		#endregion

		#region Public Members

		#region Properties
		public List<string> Messages
		{
			get { return _messages; }
		}
		public bool ShowResultMessageBox { get; private set; }
		public ITaskListService TaskListService
		{
			get { return _tasklist; }
			set { _tasklist = value; }
		}
		public bool HasErrors { get; private set; }
		public bool HasWarnings { get; private set; }
		public bool HasTasks { get; private set; }
		public bool HasUnknown { get; private set; }
		public bool IsBusy { get { return ( _worker != null ? _worker.IsBusy : false ); } }

		public Repository.Workflow Workflow
		{
			get
			{
				if ( _workflow != null ) {
					return _workflow;
				} else if ( _loader != null ) {
					return _loader.Workflow;
				}
				return null;
			}
		}
		#endregion

		#region Events
		public event EventHandler ValidationCompleted = null;
		#endregion

		#region Methods
		public void DoValidation()
		{
			_workflow = null;
			startValidation();
		}
		public void DoValidation(Repository.Workflow workflow)
		{
			_workflow = workflow;
			startValidation();
		}
		#endregion

		#endregion

		#region Private Members

		#region Constants
		private const string cValidation = "Validation";
		#endregion

		#region Variables
		private IServiceProvider _serviceProvider;
		private ITaskListService _tasklist;
		private WorkflowLoader _loader;
		private RepositoryService _repository;
		private List<string> _messages;
		private int _lastindex;
		private Repository.Workflow _workflow = null;

		// for async background validation
		//private volatile AutoResetEvent _wait = null;
		private BackgroundWorker _worker = null;
		private object lockThis = new object();

		// list for caching
		private List<LogicalCapabilityActivity> _lstLogCaps = null;
		private List<DataAggregatorActivity> _lstDataAggrs = null;
		private List<RuleEvaluatorActivity> _lstRuleEvals = null;
		private List<NotificationActivity> _lstNotifications = null;
		private List<int> _lstLogMethIds = null;
		private List<int> _lstWebServiceIds = null;
		#endregion

		#region Methods

		#region start validation
		private void startValidation()
		{
			lock ( lockThis ) {
				if ( _worker != null ) return; // EXIT

				clearTasks();

				_worker = new BackgroundWorker();
				_worker.DoWork += new DoWorkEventHandler(_worker_DoWork);
				_worker.ProgressChanged += new ProgressChangedEventHandler(_worker_ProgressChanged);
				_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_worker_RunWorkerCompleted);
				_worker.WorkerReportsProgress = true;
				_worker.WorkerSupportsCancellation = true;

				_worker.RunWorkerAsync();
			}
		}
		#endregion

		#region Background Validation
		private bool validate(BackgroundWorker bw)
		{
			validateCapabilites(bw);
			if ( bw.CancellationPending ) return true;
			validateSubscriptions(bw);
			if ( bw.CancellationPending ) return true;
			validateRuleVocabulary(bw);
			if ( bw.CancellationPending ) return true;
			validateNotifications(bw);
			if ( bw.CancellationPending ) return true;
			validateLogicalMethods(bw);
			if ( bw.CancellationPending ) return true;
			//validateMappings(bw);
			validateHumanActivities(bw);
			if ( bw.CancellationPending ) return true;
			validateWebServices(bw);
			if ( bw.CancellationPending ) return true;
			validateAggregator(bw);
			if ( bw.CancellationPending ) return true;
			validateRuleComponent(bw);
			if ( bw.CancellationPending ) return true;

			return false;
		}

		private void validateNotifications(BackgroundWorker bw)
		{
			bool hasError = false;
			foreach ( NotificationActivity notification in _lstNotifications ) {
				string name = string.IsNullOrEmpty(notification.Text) ? notification.Name : notification.Text.Replace(Environment.NewLine, " ");
				if ( string.IsNullOrEmpty(notification.NotificationHost) ||
					 string.IsNullOrEmpty(notification.NotificationSender) ) {
					addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.Notifications, notification,
						"Set the SMTP Configuration of Notification '{0}'.",
						name);
					hasError = true;
					continue;
				}
				if ( notification.Notification == null ) {
					addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.Notifications, notification,
						"The Notification Data of Notification '{0}' is empty.",
						name);
					hasError = true;
					continue;
				}
				if ( string.IsNullOrEmpty(notification.Notification.Recipient) ) {
					addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.Notifications, notification,
						"The Recipient of Notification '{0}' is empty.",
						name);
					hasError = true;
					continue;
				}
				if ( string.IsNullOrEmpty(notification.Notification.Subject) ) {
					addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.Notifications, notification,
						"The Subject of Notification '{0}' is empty.",
						name);
					hasError = true;
					continue;
				}
				if ( string.IsNullOrEmpty(notification.Notification.Message) ) {
					addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.Notifications, notification,
						"The Message of Notification '{0}' is empty.",
						name);
					hasError = true;
					continue;
				}
			}
			addTask(bw, hasError ? TaskStatus.Todo : TaskStatus.OK, WorkflowValidatorSources.Generate, null, "Notifications");
		}
		private void validateCapabilites(BackgroundWorker bw)
		{
			bool hasError = false;
			foreach ( LogicalCapabilityActivity logcap in _lstLogCaps ) {
				string name = string.IsNullOrEmpty(logcap.Text) ? logcap.Name : logcap.Text.Replace(Environment.NewLine, " ");
				if ( logcap is LogicalAsyncEndActivity ) continue;
				if ( logcap.LogicalActivityId <= 0 ) {
					addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.BusinessProcess, logcap,
							"Assign a Business Capability to the Logical Capability '{0}'.",
							name);
					hasError = true;
					continue;
				}
				Repository.LogicalActivity la = _repository.GetItem<Repository.LogicalActivity>(logcap.LogicalActivityId);
				if ( la.LogicalMethodID <= 0 || la.LogicalMethod == null ) {
					addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.Binding, logcap,
							"Bind a Logical Method to Logical Capability '{0}'.",
							name);
					hasError = true;
				} else {
					_lstLogMethIds.Add(la.LogicalMethodID);
				}
			}
			addTask(bw, hasError ? TaskStatus.Todo : TaskStatus.OK, WorkflowValidatorSources.Generate, null, "Capabilities");
		}
		private void validateSubscriptions(BackgroundWorker bw)
		{
			bool hasError = false;
			foreach ( LogicalCapabilityActivity lca in _lstLogCaps ) {
				string name = string.IsNullOrEmpty(lca.Text) ? lca.Name : lca.Text.Replace(Environment.NewLine, " ");
				Repository.LogicalActivity la = _repository.GetItem<Repository.LogicalActivity>(lca.LogicalActivityId);
				if ( la != null && la.HasInputBusinessObject ) {
					if ( la.GetSubscribedBusinessObjects().Count == 0 ) {
						addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.Subscriptions, lca,
							"The Logical Capability '{0}' requires one or more subscribed business objects.",
							name);
						hasError = true;
					} else if ( la.InputXslt == null ) {
						addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.Subscriptions, lca,
							"No subscription mapping available for the Logical Capability '{0}'.",
							name);
						hasError = true;
					}
				}
			}
			foreach ( DataAggregatorActivity daa in _lstDataAggrs ) {
				Repository.LogicalActivity la = _repository.GetItem<Repository.LogicalActivity>(daa.LogicalActivityId);
				if ( la != null ) {
					if ( la.GetSubscribedBusinessObjects().Count == 0 ) {
						addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.Subscriptions, daa,
							"The Data Aggregator '{0}' requires one or more subscribed business objects.",
							daa.Name);
						hasError = true;
					} else if ( la.InputXslt == null || string.IsNullOrEmpty(la.InputXslt.InnerXml) ) {
						addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.Subscriptions, daa,
							"No subscription mapping available for the Data Aggregator '{0}'.",
							daa.Name);
						hasError = true;
					}
				}
			}
			addTask(bw, hasError ? TaskStatus.Todo : TaskStatus.OK, WorkflowValidatorSources.Generate, null, "Subscriptions");
		}
		private void validateRuleVocabulary(BackgroundWorker bw)
		{
			bool hasError = false;
			Repository.Workflow wf = null;
			if ( _workflow != null ) {
				wf = _workflow;
			} else if ( _loader != null ) {
				wf = _loader.Workflow;
			}
			if ( wf == null ) throw new NullReferenceException("No workflow available");

			foreach ( Repository.Workflow.RuleParameterResolve rpr in
					  wf.ExtendedProperties.WorkflowVariables ) {
				if ( string.IsNullOrEmpty(rpr.ParameterResolve) ) {
					addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.Subscriptions, rpr,
						"The Rule Parameter '{0}' is not resolved.", rpr.ParameterName);
					hasError = true;
				}
			}
			addTask(bw, hasError ? TaskStatus.Todo : TaskStatus.OK, WorkflowValidatorSources.Generate, null, "Rule Vocabulary");
		}
		private void validateLogicalMethods(BackgroundWorker bw)
		{
			bool hasError = false;
			foreach ( int id in _lstLogMethIds ) {
				Repository.LogicalWebMethod lm = _repository.GetItem<Repository.LogicalWebMethod>(id);
				if ( lm != null ) {
					if ( lm.EndpointRuleID > 0 ) {
						Repository.WebService wsEP;
						foreach ( var item in lm.GetLogicalRuleResultEndpoints() ) {
							wsEP = item.ProxyWebMethodID > 0 ? item.ProxyWebService : item.WebService;
							if ( wsEP != null && !_lstWebServiceIds.Contains(wsEP.ID) ) {
								_lstWebServiceIds.Add(wsEP.ID);
							}
						}
					} else if ( lm.ProxyWebMethodID > 0 ) {
						Repository.WebService wsProxy = lm.GetAssignedProxyWebService();
						if ( wsProxy != null && !_lstWebServiceIds.Contains(wsProxy.ID) ) {
							_lstWebServiceIds.Add(wsProxy.ID);
						}
					} else {
						if ( !_lstWebServiceIds.Contains(lm.WebServiceID) ) {
							_lstWebServiceIds.Add(lm.WebServiceID);
						}
					}
					if ( lm.EndpointRuleID > 0 ) {
						foreach ( var item in lm.GetLogicalRuleResultEndpoints() ) {
							if ( item.WebMethodID <= 0 && item.ProxyWebMethodID <= 0 ) {
								addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.LogicalMethods, item,
									"The Endpoint Rule Result '{1}' of the Logical Method '{0}' " +
									"is not assigned to a web method or proxy.",
									lm.Name, item.EndpointRuleResult);
								hasError = true;
							} else {
								if ( lm.InputBusinessObjectID > 0 && item.InputXSLT == null ) {
									addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.LogicalMethods, item,
										"No input mapping for the Endpoint Rule Result '{1}' " +
										"of the Logical Method '{0}' available.",
										lm.Name, item.EndpointRuleResult);
									hasError = true;
								} else if ( lm.OutputBusinessObjectID > 0 && item.OutputXSLT == null ) {
									addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.LogicalMethods, item,
										"No output mapping for the Endpoint Rule Result '{1}' " +
										"of the Logical Method '{0}' available.",
										lm.Name, item.EndpointRuleResult);
									hasError = true;
								}
							}
						}
					} else if ( lm.WebMethodID <= 0 && lm.HumanActivityID <= 0 && lm.SendMessageQueueID <= 0 && lm.ReceiveMessageQueueID <= 0 ) {
						addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.LogicalMethods, lm,
							"The Logical Method '{0}' is not assigned to a web method or human activity.",
							lm.Name);
						hasError = true;
					} else {
						if ( lm.InputBusinessObjectID > 0 && lm.InputXSLT == null && !lm.UseInputCodeMapping ) {
							addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.LogicalMethods, lm,
								"No input mapping for the Logical Method '{0}' available.",
								lm.Name);
							hasError = true;
						} else if ( lm.OutputBusinessObjectID > 0 && lm.OutputXSLT == null && !lm.UseOutputCodeMapping ) {
							addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.LogicalMethods, lm,
								"No output mapping for the Logical Method '{0}' available.",
								lm.Name);
							hasError = true;
						}
					}
				}
			}
			addTask(bw, hasError ? TaskStatus.Todo : TaskStatus.OK, WorkflowValidatorSources.Generate, null, "Logical Methods");
		}
		private void validateMappings(BackgroundWorker bw)
		{
			bool hasError = false;
			// TODO: verify XSLT Mappings ?
			addTask(bw, hasError ? TaskStatus.Todo : TaskStatus.OK, WorkflowValidatorSources.Generate, null, "Mappings");
		}
		private void validateHumanActivities(BackgroundWorker bw)
		{
			bool hasError = false;
			foreach ( LogicalCapabilityActivity lca in _lstLogCaps ) {
				string lcaname = string.IsNullOrEmpty(lca.Text) ? lca.Name : lca.Text.Replace(Environment.NewLine, " ");
				Repository.LogicalActivity la = _repository.GetItem<Repository.LogicalActivity>(lca.LogicalActivityId);
				if ( la != null &&
					 ( la.HumanActivityID > 0 ||
					   ( la.LogicalMethodID > 0 && la.LogicalMethod != null && la.LogicalMethod.HumanActivityID > 0 ) ) ) {
					Repository.HumanActivity ha = la.GetHumanActivity();
					if ( ha == null ) ha = la.LogicalMethod.GetAssignedHumanActivity();
					if ( ha == null ) {
						addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.HumanActivities, lca,
							"The physical binding of the Logical Method '{0}' is invalid.",
							la.LogicalMethod.Name);
						hasError = true;
					} else {
						if ( string.IsNullOrEmpty(ha.FormName) || string.IsNullOrEmpty(ha.FormAssemblyName) ||
							 ha.FormDLL == null ) {
							addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.HumanActivities, lca,
								"The Human Activity '{0}' is not assigned to form.",
								ha.Name);
							hasError = true;
						}
					}
					if ( la.ExtendedProperties.HumanComponentProperties.Participants.Count == 0 ) {
						addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.Binding, lca,
							"No Participants are assigned to the Logical Capability '{0}'.",
							lcaname);
						hasError = true;
					}
				}
			}
			addTask(bw, hasError ? TaskStatus.Todo : TaskStatus.OK, WorkflowValidatorSources.Generate, null, "Human Activities");
		}
		[DebuggerStepThrough]
		private void validateWebServices(BackgroundWorker bw)
		{
			bool hasError = false;
			bool allErrorsUnknown = true;
			foreach ( int idWS in _lstWebServiceIds ) {
				Repository.WebService ws = _repository.GetItem<Repository.WebService>(idWS);
				if ( ws == null ) continue;
				string serviceUrl = ws.Uri;
				string sourceUrl = ws.Uri;
				if ( !sourceUrl.ToLower().EndsWith("?wsdl") )
					sourceUrl += "?wsdl";

				System.ServiceModel.Description.MetadataExchangeClient mclient;
				System.ServiceModel.Description.MetadataSet mset = null;

				if ( sourceUrl.StartsWith("http") ) {
					//mclient = new System.ServiceModel.Description.MetadataExchangeClient
					//    (new Uri(sourceUrl), System.ServiceModel.Description.MetadataExchangeClientMode.HttpGet);
					mclient = new MetadataExchangeClient("metadataBinding");
					try {
						//mset = mclient.GetMetadata();
						mset = mclient.GetMetadata(new Uri(sourceUrl), System.ServiceModel.Description.MetadataExchangeClientMode.HttpGet);
					} catch ( Exception ex ) {
						if ( ex.InnerException != null ) {
							addTask(bw, TaskStatus.Unknown, WorkflowValidatorSources.WebServices,
								"Error while request WSDL from Web Service '{0}': {1}",
								ws.Name, ex.InnerException.Message);
							hasError = true;
							allErrorsUnknown = false;
						} else {
							addTask(bw, TaskStatus.Unknown, WorkflowValidatorSources.WebServices,
								"Error while request WSDL from Web Service '{0}': {1}",
								ws.Name, ex.Message);
							hasError = true;
							allErrorsUnknown = false;
						}
						continue;
					}
				} else {
					continue;
				}
				System.Web.Services.Description.ServiceDescription _wsdl = null;
				System.ServiceModel.Description.WsdlImporter importer =
					new System.ServiceModel.Description.WsdlImporter(mset);
				if ( importer.WsdlDocuments.Count > 0 ) {
					_wsdl = importer.WsdlDocuments[0];
				}

				// found wsdl document?
				if ( _wsdl != null ) {
					XmlSchemaSet xsdSet = createXmlSchemaSet();

					//add WSDL Document Namespaces to the Schema Builder
					foreach ( XmlSchema xsd in _wsdl.Types.Schemas ) {
						if ( !xsdSet.Contains(xsd.TargetNamespace) )
							xsdSet.Add(xsd);
					}
					foreach ( XmlSchema xsd in importer.XmlSchemas.Schemas() ) {
						if ( !xsdSet.Contains(xsd.TargetNamespace) )
							xsdSet.Add(xsd);
					}
					xsdSet.Compile();
					//_wsdl.Types.Schemas.Clear();
					foreach ( XmlSchema xsd in xsdSet.Schemas() ) {
						_wsdl.Types.Schemas.Add(xsd);
					}
					_wsdl.Types.Schemas.Compile(null, true);
					System.ServiceModel.Description.ContractDescription cdesc =
						importer.ImportContract(_wsdl.PortTypes[0]);
				}
				string strMetaData = "";
				using ( StringWriter sw = new StringWriter() )
				using ( XmlWriter xw = XmlWriter.Create(sw) ) {
					mset.WriteTo(xw);
					xw.Flush();
					strMetaData = sw.ToString();
				}
				if ( ws.MetaData != strMetaData ) {
					addTask(bw, TaskStatus.Unknown, WorkflowValidatorSources.WebServices, ws,
						"The Web Service '{0}' was changed. You can update this Web Service in the Details View.",
						ws.Name);
					hasError = true;
					continue;
				}
			}
			addTask(bw, hasError ? ( allErrorsUnknown ? TaskStatus.Unknown : TaskStatus.Todo ) : TaskStatus.OK, WorkflowValidatorSources.Generate, null, "Web Services");
			//#endif
		}
		private XmlSchemaSet createXmlSchemaSet()
		{
			XsdDataContractExporter ex = new XsdDataContractExporter();
			ex.Export(typeof(OpenComposite.EII.Designer.Workflow.Help));
			XmlSchemaSet xsdset = ex.Schemas;
			XmlSchema xsdRemove = null;
			foreach ( XmlSchema xsd in xsdset.Schemas() ) {
				if ( xsd.Elements.Contains(new XmlQualifiedName("Help", xsd.TargetNamespace)) ) {
					xsdRemove = xsd;
				}
			}
			xsdset.Remove(xsdRemove);
			return xsdset;
		}
		private void validateAggregator(BackgroundWorker bw)
		{
			bool hasError = false;
			if ( _lstDataAggrs != null && _lstDataAggrs.Count > 0 ) {
				foreach ( DataAggregatorActivity da in _lstDataAggrs ) {
					Repository.LogicalActivity la = _repository.GetItem<Repository.LogicalActivity>(da.LogicalActivityId);
					if ( la == null ) {
						addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.BusinessProcess, da,
							"The Data Aggregator '{0}' is not configurated.", da.Name);
						hasError = true;
					} else {
						if ( la.GetOutputBusinessObject() == null ) {
							addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.BusinessProcess, da,
								"The Data Aggregator '{0}' has no output business object.", da.Name);
							hasError = true;
						}
						if ( la.InputXslt == null || string.IsNullOrEmpty(la.InputXslt.InnerXml) ) {
							addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.BusinessProcess, da,
								"The Data Aggregator '{0}' mapping is missing.", da.Name);
							hasError = true;
						}
					}
				}
			}
			addTask(bw, hasError ? TaskStatus.Todo : TaskStatus.OK, WorkflowValidatorSources.Generate, null, "Aggregators");
		}
		private void validateRuleComponent(BackgroundWorker bw)
		{
			bool hasError = false;
			if ( _lstRuleEvals != null && _lstRuleEvals.Count > 0 ) {
				foreach ( RuleEvaluatorActivity ruleact in _lstRuleEvals ) {
					Repository.LogicalActivity la = _repository.GetItem<Repository.LogicalActivity>(ruleact.LogicalActivityId);
					if ( la == null ) {
						addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.BusinessProcess, ruleact,
							"The Rule Evaluator '{0}' is not configurated.", ruleact.Name);
						hasError = true;
					} else {
						if ( la.GetOutputBusinessObject() == null ) {
							addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.BusinessProcess, ruleact,
								"The Rule Evaluator '{0}' has no output business object.", ruleact.Name);
							hasError = true;
						}
						if ( la.GetBusinessRule() == null ) {
							addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.BusinessProcess, ruleact,
								"The Rule Evaluator '{0}' is not assigned to a business rule.", ruleact.Name);
							hasError = true;
						}
						if ( string.IsNullOrEmpty(la.ExtendedProperties.BusinessRuleOutputPath) ) {
							addTask(bw, TaskStatus.Todo, WorkflowValidatorSources.BusinessProcess, ruleact,
								"The Rule Evaluator '{0}' Output Path is missing.", ruleact.Name);
							hasError = true;
						}
					}
				}
			}
			addTask(bw, hasError ? TaskStatus.Todo : TaskStatus.OK, WorkflowValidatorSources.Generate, null, "Rule Components");
		}
		#endregion

		#region clear / add tasks
		private void clearTasks()
		{
			_lastindex = -1;
			if ( _tasklist != null ) {
				if ( _workflow != null ) {
					_tasklist.Clear(_workflow, cValidation);
				} else if ( _loader != null ) {
					_tasklist.Clear(_loader.Workflow, cValidation);
				}
			} else {
				_messages.Clear();
			}
		}

		//private void addTask(BackgroundWorker bw, TaskStatus status, string sourceName, IRepositoryItem item, string descriptionFormat, params object[] args)
		//{
		//    addTask(bw, status, sourceName, item, descriptionFormat, args);
		//}
		private void addTask(BackgroundWorker bw, TaskStatus status, string sourceName, object tag, string descriptionFormat, params object[] args)
		{
			if ( bw != null ) {
				bw.ReportProgress(0, new _task(status, sourceName, tag, descriptionFormat, args));
			} else {
				addTask(status, sourceName, tag, descriptionFormat, args);
			}
		}
		//private void addTask(TaskStatus status, string sourceName, IRepositoryItem item, string descriptionFormat, params object[] args)
		//{
		//    addTask(status, sourceName, item, descriptionFormat, args);
		//}
		private void addTask(TaskStatus status, string sourceName, object tag, string descriptionFormat, params object[] args)
		{
			if ( _tasklist != null ) {
				Repository.Workflow wf = this.Workflow;
				if ( wf != null ) {
					_lastindex = _tasklist.Insert(wf,
												  _lastindex + 1,
												  TaskItemType.Task,
												  status, wf,
												  string.Format(descriptionFormat, args),
												  cValidation,
												  sourceName);
				} else {
					throw new NullReferenceException("No workflow available.");
				}
			} else {
				string msg = string.Format("({0}) {1}: {2}",
											sourceName,
											string.Format(descriptionFormat, args),
											status);
				_messages.Add(msg);
				Debug.WriteLine("[WFValidator]" + msg);
			}
		}
		#endregion

		#region get activities
		private List<T> getLogicalActivities<T>() where T : System.Workflow.ComponentModel.Activity
		{
			CompositeActivity composite = null;
			List<T> lstLogActs = new List<T>();

			IDesignerHost designerHost = _serviceProvider.GetService(typeof(IDesignerHost)) as IDesignerHost;
			if ( _workflow != null ) {
				composite = Helpers.GetRootActivity(_workflow) as CompositeActivity;
			} else if ( designerHost != null && designerHost.RootComponent is CompositeActivity ) {
				composite = (CompositeActivity)designerHost.RootComponent;
			} else if ( _serviceProvider is Repository.Workflow ) {
				composite = Helpers.GetRootActivity((Repository.Workflow)_serviceProvider) as CompositeActivity;
			}
			if ( composite != null ) {
				foreach ( Activity act in Helpers.GetNestedActivities(composite) ) {
					if ( act is T ) lstLogActs.Add((T)act);
				}
			}
			return lstLogActs;
		}
		#endregion

		#region validation completed
		private void onValidationCompleted()
		{
			EventHandler tmp = this.ValidationCompleted;
			if ( tmp != null ) {
				tmp(this, EventArgs.Empty);
			}
		}
		#endregion

		#endregion

		#region Event Handlers
		private void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
		{
			if ( !e.Cancelled && _tasklist == null && _messages != null && _messages.Count > 0 ) {
				string msg = string.Join(Environment.NewLine, _messages.ToArray());
				MessageBox.Show(msg, "Validation Completed", MessageBoxButtons.OK, MessageBoxIcon.Information);
			}
			lock ( lockThis ) {
				_worker.Dispose();
				_worker = null;
			}
			onValidationCompleted();
		}
		private void _worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
		{
			_task t = e.UserState as _task;
			if ( t != null ) {
				if ( t.Status == TaskStatus.Todo ) {
					this.HasTasks = true;
				} else if ( t.Status == TaskStatus.Unknown ) {
					this.HasUnknown = true;
				}
				addTask(t.Status, t.SourceName, t.Tag, t.DescriptionFormat, t.Args);
			}
		}
		private void _worker_DoWork(object sender, DoWorkEventArgs e)
		{
			_lstLogCaps = getLogicalActivities<LogicalCapabilityActivity>();
			_lstDataAggrs = getLogicalActivities<DataAggregatorActivity>();
			_lstRuleEvals = getLogicalActivities<RuleEvaluatorActivity>();
			_lstNotifications = getLogicalActivities<NotificationActivity>();
			_lstLogMethIds = new List<int>();
			_lstWebServiceIds = new List<int>();

			e.Cancel = validate(sender as BackgroundWorker);

			_lstLogCaps.Clear(); _lstLogCaps = null;
			_lstDataAggrs.Clear(); _lstDataAggrs = null;
			_lstRuleEvals.Clear(); _lstRuleEvals = null;
			_lstLogMethIds.Clear(); _lstLogMethIds = null;
			_lstWebServiceIds.Clear(); _lstWebServiceIds = null;

			//onValidationCompleted();
		}
		#endregion

		#endregion

		#region Private Class: _task
		private class _task
		{
			public _task(TaskStatus status, string sourceName, object tag, string descriptionFormat, params object[] args)
			{
				Status = status;
				SourceName = sourceName;
				DescriptionFormat = descriptionFormat;
				Args = args;
				Tag = tag;
			}
			public TaskStatus Status;
			public string SourceName;
			public string DescriptionFormat;
			public object[] Args;
			public object Tag;
		}
		#endregion
	}
}

